package com.xm.web.exception;

import com.xm.common.entity.R;
import com.xm.common.entity.ResConst;
import com.xm.common.utils.StrPool;
import com.xm.security.exception.ExceptionAdviceHandler;
import io.jsonwebtoken.JwtException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ValidationException;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 *
 * @author yousj
 * @version 1.0.0
 * @since 2021/8/20 9:20
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionAdvice implements ExceptionAdviceHandler {

    @SneakyThrows
    @Override
    public void accessDeniedHandler(Exception e, HttpServletResponse response) {
        r(response, globalHandler(e));
    }

    @SneakyThrows
    @Override
    public void authenticationEntryPointHandler(Exception e, HttpServletResponse response) {
        r(response, globalHandler(e));
    }

    @SneakyThrows
    @Override
    public void handler(Exception e, HttpServletResponse response) {
        r(response, globalHandler(e));
    }

    @ExceptionHandler(Exception.class)
    public R globalHandler(Exception e) {
        R r;
        if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
            r = R.isFail(ResConst.USER_ERROR);
        } else if (e instanceof AccountExpiredException) {
            r = R.isFail(ResConst.UNAUTHORIZED_ERROR);
        } else if (e instanceof AuthenticationException || e instanceof AccessDeniedException) {
            r = R.isFail(ResConst.FORBIDDEN_ERROR);
        } else if (e instanceof JwtException) {
            r = R.isFail(ResConst.TOKEN_EXPIRE);
        } else if (e instanceof ValidationException) {
            r = R.isFail(ResConst.BAD_REQUEST, e.getMessage());
        } else if (e instanceof NoHandlerFoundException) {
            r = R.isFail(ResConst.NOT_FOUND_ERROR);
        } else if (e instanceof HttpRequestMethodNotSupportedException) {
            r = R.isFail(ResConst.METHOD_NOT_ALLOWED);
        } else if (e instanceof BusinessException) {
            BusinessException be = (BusinessException) e;
            r = R.isFail(be.getCode(), be.getMessage());
        } else if (e instanceof BindException) {
            r = R.isFail(ResConst.BAD_REQUEST, ((BindException) e).getFieldErrors()
                    .stream()
                    .map(DefaultMessageSourceResolvable::getDefaultMessage)
                    .collect(Collectors.joining(StrPool.COMMA)));
        } else {
            log.error("web global exception msg {} ", e.getMessage(), e);
            r = R.isFail(ResConst.SYSTEM_ERROR);
        }
        return r;
    }

}
